#~/usr/bin/perl -w

use warnings;
use strict;
use List::MoreUtils 'any';

########################################
# emailStats.perl
# v0.1 05/28/2010 by pmhesse
# uses spotlight metadata functions mdfind and mdls to obtain statistics for the email on your system
# creates CSV output containing all the email addresses found, # sent to those users, # sent from, total bytes
# To use: edit the startPath and myEmail variables below
# then run 'perl emailStats.perl >myOutput.csv' at a command line (it takes a while!!)
########################################

my $startPath = "~/Library/Mail/"; 
my $myEmail = "testuser\@testdomain.com"; # only count emails to or from this address - all lowercase, escape at symbol

########################################
# you shouldn't have to edit anything from here down below.
# todo: some sort of progress meter
########################################

# our main storage (listOfEmails) is a hash of arrays - http://perldoc.perl.org/perldsc.html
# the key to the hash is the email address, the inner array is:
# [0] # it appears as recipient | [1] # it appears as sender | [2] total fileSize (bytes)
my %listOfEmails;

# find all email files in the path specified
my @filelist = `mdfind -onlyin $startPath "kMDItemContentType == 'com.apple.mail.emlx'"`;
chomp @filelist;

# in case the directions weren't followed, convert the myEmail to lowercase
$myEmail = lc($myEmail);

# go through all the files found
for my $filename ( @filelist ) {
	# add all the recipients in that file to an array
	my @recipients = `mdls -name kMDItemRecipientEmailAddresses -raw "$filename"`;
	chomp @recipients;
	# add all the senders in that file to an array
	my @senders = `mdls -name kMDItemAuthorEmailAddresses -raw "$filename"`;
	chomp @senders;

	# clean up the arrays (the mdls output includes extra lines)
	shift(@recipients); #get rid of first line (a paren)
	pop(@recipients); #get rid of last line (a paren)
	shift(@senders); #get rid of first line (a paren)
	pop(@senders); #get rid of last line (a paren)

	# get the size of the file
	my $fileSize = `mdls -name kMDItemFSSize -raw "$filename"`;

	# convert both arrays to all lowercase
	my @lcRecipients = map { lc } @recipients;
	my @lcSenders = map { lc } @senders;

	# find if my address was the sender or a recipient
	my $isent = any { /$myEmail/ } @lcSenders;
	my $irecd = any { /$myEmail/ } @lcRecipients;

	if ($isent || $irecd)
	{
		if ($isent)
		{
			# if I appeared as a sender, we're counting all the people I sent to
			for my $recip ( @recipients ) 
			{
				$recip =~ s/( |\"|,)//g; 	# strip extra characters from mdls output
				$listOfEmails{lc($recip)}[0]++; # add this as a time this appeared as a recipient

				# if there is no existing record for the # of times appearing as sender, set it to 0
				unless ($listOfEmails{lc($recip)}[1])
				{	
					$listOfEmails{lc($recip)}[1] = 0;	
				}

				# if there is no existing record for the size, set it to the size of this message, otherwise add it
				if ($listOfEmails{lc($recip)}[2])
				{
					$listOfEmails{lc($recip)}[2] = $listOfEmails{lc($recip)}[2] + $fileSize;
				}
				else
				{
					$listOfEmails{lc($recip)}[2] = $fileSize;
				}
			}
		}
		elsif ($irecd)
		{
			# if I appeared as a recipient, we're counting the sender(s) only.
			for my $send ( @senders ) 
			{
				$send =~ s/( |\"|,)//g;		# strip extra characters from mdls output
				$listOfEmails{lc($send)}[1]++;	# add this as a time this appeared as a sender

				# if there is no existing record for the # of times appearing as recipient, set it to 0
				unless ($listOfEmails{lc($send)}[0])
				{
					$listOfEmails{lc($send)}[0] = 0;
				}

				# if there is no existing record for the size, set it to the size of this message, otherwise add it
				if ($listOfEmails{lc($send)}[2])
				{
					$listOfEmails{lc($send)}[2] = $listOfEmails{lc($send)}[2] + $fileSize;
				}
				else
				{
					$listOfEmails{lc($send)}[2] = $fileSize;
				}
			}
		}
	}
}

#output csv format
printf("email address,number sent to,number received from,total size exchanged with that user (bytes)\n");
for my $key (keys(%listOfEmails)) { printf("%s,%d,%d,%d\n",$key,$listOfEmails{$key}[0],$listOfEmails{$key}[1],$listOfEmails{$key}[2]); }
